<?php

namespace App\Services;
use App\Jobs\Process485;
use App\Models\Device;
use App\Models\Device485;
use Workerman\Timer;
use Illuminate\Support\Facades\Redis;
use Workerman\Mqtt\Client;



class DeviceModelService
{
    protected $timers;

    protected $mqttClient;

    public function __construct(Client $mqttClient)
    {
        $this->mqttClient = $mqttClient;
        $this->timers = []; // 保存相关485网关的定时器任务
        $this->updateDevice();
    }

    /**
     * @return void 主要是定时去更新设备的数据
     */
    protected function updateDevice()
    {
        Timer::add(5, function () { // 每隔1分钟检测一次数据库的值, 查询有没有新建的设备
            $devices = $this->getActiveDevices();
            foreach ($devices as $device) {
                if (empty($device->deviceModel->ror_second)) {
                    continue; // 如果间隔为0, 则跳出循环
                }
                $this->managerTimer($device); // 主要是处理timer类
            }
        });
    }

    /**
     * @param $device
     * @return void  处理相关timer
     */
    protected function managerTimer($device)
    {
        // 首先检测数据库的最新ror_second对不对，
        if (isset($this->timers[$device->id]) && $this->timers[$device->id]['interval'] != $device->deviceModel->ror_second) {
            // echo 'time_del: ' . $this->timers[$device->id]['timer_id'] . PHP_EOL;
            Timer::del($this->timers[$device->id]['timer_id']);
            unset($this->timers[$device->id]);
        }
        // 如果不存在，则表示新增，需创建timer数组
        if (!isset($this->timers[$device->id])) {
            $timer_id = Timer::add($device->deviceModel->ror_second, function() use ($device){
                // 执行实际业务代码
                $this->executeDeviceTask($device);
            });
            // echo 'time: ' . $timer_id . PHP_EOL;
            $this->timers[$device->id] = [
                'timer_id' => $timer_id,
                'interval' => $device->deviceModel->ror_second
            ];
        }
    }

    /**
     * @param $device
     * @return void 实际执行业务的方法
     */
    protected function executeDeviceTask($device)
    {
        if ($device->deviceModel->attr) { // 有属性的话才执行逻辑
            $array = $device->deviceModel->attr->toArray();
            foreach ($array as $v) {
                $this->sendBinary($device, $v['start_address'], $v['register_num'], $v['byte_num']);
            }
        }
    }

    /**
     * @param $device
     * @param $start string
     * @param $registerNum string
     * @param $byteNum  int 返回的字节数
     * @return void
     */
    protected function sendBinary($device, $start, $registerNum, $byteNum)
    {
        $str = $device->address . $device->deviceModel->read_code . $start . $registerNum;
        $data = strToBinary($str); // 字符串转2进制
        $crc = calculateModbusCRC($data); // 算出modbus rtu的crc码
        $fullCode = $str.$crc;
        //$binaryData = hex2bin($fullCode);  // 将16进制字符串转换为二进制数据
        Process485::dispatch($fullCode, $device->id); // 这里可以分隔队列进行处理
        //$this->mqttClient->publish('/whd1/network/test/r/1234', $binaryData);


    }

    /**
     * @return mixed
     */
    public function getActiveDevices()
    {
        // "select * from `device_485` where (select count(*) from `devices` where `device_485`.`device_id` = `devices`.`id` and `id` < ? and `devices`.`deleted_at` is null) > 10 and `device_485`.`deleted_at` is null"
        // $device485 = Device485::whereHas('Device', function($query) {
        //            return $query->where('id', '<',  3);
        //        }, '>', 10)->get();
        // select * from `device_485` where exists (select * from `devices` where `device_485`.`device_id` = `devices`.`id` and `id` < ? and `devices`.`deleted_at` is null) and `device_485`.`deleted_at` is null
//         $device485 = Device485::whereHas('Device', function($query) {
//                    return $query->where('id', '<',  3);
//                })->get();
        //\DB::enableQueryLog(); // 开启查询日志
        $device485 = Device485::whereHas('device')->with('deviceModel.attr')->get();
        //$sql = \DB::getQueryLog();
        //var_dump($sql);
        return $device485;
    }

}

